<template>
  <div>
    <ul v-if="files.length>0 && enableList" :class="size">
      <li v-for="item of files" :key="item.name" :class="item.complete">
        {{getName(item.name)}}({{getBytesWithUnit(item.data.size, true, 2, true)}})
        <div class="up-progress" :style="{width:item.upprogress}">{{item.upprogress}}</div>
        <div class="parse-progress" :style="{width:item.parseprogress}">{{item.parseprogress}}</div>
        <span
          v-if="item.hash != ''"
          class="item-action"
          :class="{'action-upload':item.upprogress != '0%' && item.upprogress != '100%','action-finished':item.upprogress == '100%','action-stop':item.upprogress == '0%'}"
          @click="uploadItem(item.name)"
          @mouseover="mouseOver(item.name)"
        ></span>
        <span class="item-closer" @click="removeItem(item.name)"></span>
      </li>
    </ul>
  </div>
</template>
<script>
/* eslint-disable */
import Worker from "./upload.worker.js";
export default {
  name: "FileList",
  props: {
    files: { required: true, default: [] },
    apiUrl: { type: String, required: true },
    enableList: { type: Boolean, default: true },
    autoRemove: { type: Boolean, default: false },
    removeDelay: { type: Number, default: 2000 },
    size: { type: String, default: "small" },
    storeDir: { type: String, default: "/fs" },
    storeType: { type: String, default: "0" }, //0-local 1-hdfs 2-gridfs
    headers: { type: Object },
    chunkSize: { type: Number, default: 4 * 1024 * 1024 },
  },
  computed: {},
  created() {},
  mounted() {
    this.$on("addItem", (res) => {
      this.createItem(res);
    });
  },
  methods: {
    uploadItem(name) {
      let index = this.files.findIndex((v) => v.name === name);
      let item = this.files[index];
      //when miss hash do nothing
      if (item.hash == "") return;
      if (item.upprogress != "0%") {
        this.warn(item.name + " 文件正在上传，请稍后");
        return;
      }
      item.upprogress = "0.01%";
      let worker = new Worker();
      worker.postMessage({
        type: "upload",
        data: item,
        options: {
          baseUrl: this.apiUrl,
          chunkSize: this.chunkSize,
          headers: Object.assign(
            {
              "Store-Dir": this.storeDir,
              "Store-Type": this.storeType,
            },
            this.headers
          ),
        },
      });
      worker.onmessage = (e) => {
        var data = e.data;
        switch (data.cmd) {
          case "init":
            console.log("线程初始化");
            break;
          case "progress":
            item.upprogress = data.data.percent + "%";
            break;
          case "complete":
            item.parseprogress = "100%";
            item.upprogress = "100%";
            item.complete = "complete";
            if (this.autoRemove) {
              setTimeout(() => {
                this.removeItem(item.name);
              }, this.removeDelay);
            }
            setTimeout(() => {
              this.success(this.getName(item.name) + " 上传成功");
            }, 10);
            break;
          case "check-file-error":
            debugger;
            item.complete = "error";
            item.upprogress = "0%";           
            this.error(this.getName(item.name) + " 文件检查请求失败");            
            break;
          case "make-file-error":
            debugger;
            item.complete = "error";
            item.upprogress = "0%";           
            this.error(this.getName(item.name) + " 创建文件请求失败");
            break;
          case "chunk-exist":
            this.success(
              this.getName(item.name) + "[" + data.data.index + "]" + " 片续传完成"
            );
            break;
          case "upload-chunck-retry":
            item.complete = "warn";
            this.warn(
              this.getName(item.name) +
                "[" +
                data.data.index +
                "] retry:" +
                data.data.retry_times
            );
            break;
          case "upload-chunck-error":            
            item.complete = "error";
            item.upprogress = "0%";            
            this.warn(
              this.getName(item.name) + "[" + data.data.index + "]" + " 片上传请求失败"
            );
            break;
          case "worker-error":
            debugger;
            item.complete = "error";
            this.error("工作线程异常");
            break;
          default:
            // statements_def
            break;
        }
      };
      worker.onerror = (erro) => {
        worker.terminate();
      };
    },
    createItem(name) {
      let index = this.files.findIndex((v) => v.name === name);
      let item = this.files[index];
      let worker = new Worker();
      worker.postMessage({
        type: "add",
        data: item,
        options: {},
      });
      worker.onmessage = (e) => {
        var data = e.data;
        switch (data.cmd) {
          case "init":
            console.log("线程初始化");
            break;
          case "parse-complete":
            this.files[index].hash = data.data.hash;
            if (!this.enableList) {
              this.uploadItem(name);
            }
            break;
          case "parsed":
            //console.log("parsed", data.data.name, data.data.id);
            break;
          case "loaded":
            item.parseprogress = data.data.percent + "%";
            break;
          case "progress":
            item.upprogress = data.data.percent + "%";
            break;
          case "worker-error":
            this.error("工作线程异常");
            break;
          default:
            // statements_def
            break;
        }
      };

      worker.onerror = (erro) => {
        worker.terminate();
      };
    },
    removeItem(name) {
      this.files.splice(
        this.files.findIndex((v) => v.name === name),
        1
      );
    },
    mouseOver(name) {
      let index = this.files.findIndex((v) => v.name === name);
      let item = this.files[index];
    },
    getName(name) {
      if (name.length > 20) {
        return name.substring(0, 17) + "...";
      } else {
        return name;
      }
    },
    getBytesWithUnit(bytes, useSI, precision, useSISuffix) {
      "use strict";
      if (!(!isNaN(bytes) && +bytes > -1 && isFinite(bytes))) {
        return false;
      }
      var units, obj, amountOfUnits, unitSelected, suffix;
      units = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
      obj = {
        base: useSI ? 10 : 2,
        unitDegreeDiff: useSI ? 3 : 10,
      };
      amountOfUnits = Math.max(
        0,
        Math.floor(
          Math.round((Math.log(+bytes) / Math.log(obj.base)) * 1e6) / 1e6
        )
      );
      unitSelected = Math.floor(amountOfUnits / obj.unitDegreeDiff);
      unitSelected =
        units.length > unitSelected ? unitSelected : units.length - 1;
      suffix =
        useSI || useSISuffix
          ? units[unitSelected]
          : units[unitSelected].replace("B", "iB");
      bytes = +bytes / Math.pow(obj.base, obj.unitDegreeDiff * unitSelected);
      precision = precision || 3;
      if (
        bytes.toString().length > bytes.toFixed(precision).toString().length
      ) {
        bytes = bytes.toFixed(precision);
      }
      return bytes + " " + suffix;
    },
    error(msg) {
      if (this.$messagebox !== undefined) {
        this.$messagebox({
          content: msg,
          type: "error", //'success','warning','error'
        });
      } else {
        console.error(msg);
      }
    },
    warn(msg) {
      if (this.$messagebox !== undefined) {
        this.$messagebox({
          content: msg,
          type: "warning", //'success','warning','error'
        });
      } else {
        console.warn(msg);
      }
    },
    success(msg) {
      if (this.$messagebox !== undefined) {
        this.$messagebox({
          content: msg,
          type: "success", //'success','warning','error'
        });
      } else {
        console.log(msg);
      }
    },
  },
};
</script>
<style scoped>
ul {
  padding: 0.7em;
  position: absolute;
  bottom: 0;
  right: 0;
  display: block;
  transform: translateZ(0);
  backface-visibility: hidden;
  min-width: 160px;
  max-width: 240px;
}

ul li {
  padding: 0.7em;
  list-style: none;
  display: block;
  background-color: #f2f2f2;
  margin-bottom: 0.3em;
  color: #000;
  font-size: 0.5em;
  text-align: left;
  position: relative;
  outline: 1px solid rgba(0, 0, 0, 0.1);
  transition: all 300ms 0s;
  animation: fade-in 300ms 0s;
  transform: translateZ(0);
  backface-visibility: hidden;
  max-height: 30px;
  /* overflow: hidden; */
}

li > .up-panel {
  border-radius: 5px;
}

li > .up-progress {
  display: block;
  background-color: rgba(255, 0, 104, 0.61);
  text-align: center;
  line-height: 0.2em;
  overflow: hidden;
  text-indent: -1000%;
  position: absolute;
  bottom: 0;
  left: 0;
  z-index: -1;
  transition: all 200ms 0s;
  max-height: 30px;
}

li > .parse-progress {
  display: block;
  background-color: rgba(28, 105, 9, 0.8);
  text-align: center;
  line-height: 0.2em;
  overflow: hidden;
  text-indent: -1000%;
  margin-top: 0;
  position: absolute;
  bottom: 0.2em;
  left: 0;
  z-index: -1;
  transition: all 200ms 0s;
  max-height: 30px;
}

li > .item-action {
  width: 16px;
  height: 16px;
  line-height: 12px;
  text-align: center;
  /* border-radius: 2px; */
  font-size: 26px;
  padding: 0px 5px 5px 0px;
  /* background-color: #409eff; */
  border: 1px solid rgba(250, 250, 250, 0);
  /* box-shadow: inset 0px 0px 0.5em rgba(0, 0, 0, 0.5); */
  z-index: 10;
  transform: rotate(-90deg) scaleX(1) scaleY(0.7);
  -ms-transform: rotate(-90deg) scaleX(1) scaleY(0.7); /* Internet Explorer 9*/
  -moz-transform: rotate(-90deg) scaleX(1) scaleY(0.7); /* Firefox */
  -webkit-transform: rotate(-90deg) scaleX(1) scaleY(0.7); /* Safari 和 Chrome */
  -o-transform: rotate(-90deg) scaleX(1) scaleY(0.7); /* Opera */
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
}

.item-action {
  top: 2px;
  left: -12px;
  position: absolute;
}

li > .item-action:before {
  content: "\25BC";
}

li > .action-upload {
  color: #13b903;
}

li > .action-finished {
  color: #409eff;
  display: none;
}

li > .action-stop {
  color: #5d5e61;
}

li > .item-closer {
  width: 16px;
  height: 16px;
  line-height: 16px;
  text-align: center;
  border-radius: 10px;
  color: #ffffff;
  font-size: 12px;
  padding: 1px;
  background-color: #409eff;
  border: 1px solid rgba(0, 0, 0, 0.1);
  /* box-shadow: inset 0px 0px 0.5em rgba(0, 0, 0, 0.5); */
  z-index: 10;
}

li > .item-closer:before {
  content: "\2716";
}

.item-closer {
  top: -8px;
  right: -8px;
  position: absolute;
}

ul li.error {
  color: red;
  transition-delay: 500ms;
}

ul li.warn {
  color: rgb(231, 179, 5);
  transition-delay: 500ms;
}

ul li.error:after {
  content: "\2716";
  display: block;
  float: right;
  text-align: right;
  padding-left: 0.5em;
  margin-left: 0.5em;
  color: #ff0000;
  border-left: 1px solid rgba(0, 0, 0, 0.1);
}

ul li.complete {
  color: white;
  transition-delay: 500ms;
}

ul li.complete:after {
  content: "\2714";
  display: block;
  float: right;
  text-align: right;
  padding-left: 0.5em;
  margin-left: 0.5em;
  color: #ff0000;
  border-left: 1px solid rgba(0, 0, 0, 0.1);
}

ul li.complete .up-progress {
  background-color: rgba(28, 105, 9, 0.8);
  line-height: 3em;
  z-index: -2;
  transition-delay: 500ms;
}

ul li.complete .parse-progress {
  background-color: rgba(28, 105, 9, 0);
  line-height: 3em;
  z-index: -3;
  transition-delay: 500ms;
}

@keyframes fade-in {
  0% {
    opacity: 0;
    top: 1em;
  }
  100% {
    top: 0em;
  }
}
</style>